package nl.justobjects.pushlet.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import nl.justobjects.pushlet.util.Log;

public class EventCache {
	
	private static EventCache instance = new EventCache();
	private HashMap<String, Event> eventCache;
	private List<String> cacheNeedRecover;
	private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);
	
	private EventCache() {
		
	}
	
	public static EventCache getInstance() {
		return instance;
	}
	
	public void start(int initialCapacity) {
		eventCache = new HashMap<String, Event>(initialCapacity);
		cacheNeedRecover = new ArrayList<String>();
		// 每小时扫描一次，回收待回收的缓存
		scheduledThreadPoolExecutor.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				synchronized (cacheNeedRecover) {
					for (String subject: cacheNeedRecover) {
						removeCache(subject);
						cacheNeedRecover.remove(subject);
					}
				}
			}
		}, 1L, 1L, TimeUnit.HOURS);
	}
	
	public void stop() {
		scheduledThreadPoolExecutor.shutdownNow();
		eventCache.clear();
		cacheNeedRecover.clear();
	}
	
	public void putEvent(Event event) {
		String compositeSubject = Subscription.compositeSubject(event.getSubject(), (String) event.getField(Protocol.P_LABEL));
		synchronized (eventCache) {
			eventCache.put(compositeSubject, event);
		}
		Log.info("[EventCache]putEvent of subject: " + compositeSubject + ", event: " + event.toString());
	}
	
	public Event getEvent(String compositeSubject) {
		Event event = null;
		synchronized (eventCache) {
			event = eventCache.get(compositeSubject);
		}
		Log.info("[EventCache]getEvent of subject: " + compositeSubject + ", cache " + ((event == null) ? "not get" : "get"));
		if (event != null) {
			// 将该主题从待回收列表中删除
			recoverOut(compositeSubject);
		}
		return event;
	}
	
	public void removeCache(String compositeSubject) {
		Log.info("[EventCache]removeCache of subject: " + compositeSubject);
		synchronized (eventCache) {
			eventCache.remove(compositeSubject);
		}	
	}
	
	public void recoverIn(String compositeSubject) {
		Log.info("[EventCache]recoverIn of subject: " + compositeSubject);
		synchronized (cacheNeedRecover) {
			cacheNeedRecover.add(compositeSubject);
		}
	}
	
	public void recoverOut(String compositeSubject) {
		Log.info("[EventCache]recoverOut of subject: " + compositeSubject);
		synchronized (cacheNeedRecover) {
			cacheNeedRecover.remove(compositeSubject);
		}
	}
}
